<template>
  <v-popover
    :model-value="modelValue"
    @update:model-value="updateHandle"
  >
    <view class="v-picker-container">
      <view class="header">
        <view
          class="cancel-button"
          @click="hidePicker"
        >
          取消
        </view>
        <view class="content">
          <slot name="header" />
        </view>
        <view
          v-if="isClear"
          class="clear-button"
          @click="clearHandle"
        >
          清除
        </view>
        <view
          class="confirm-button"
          @click="confirmHandle"
        >
          确定
        </view>
      </view>
      <view class="divider" />
      <template v-if="$slots.default">
        <slot />
        <view class="divider" />
      </template>
      <picker-view
        :value="optionsIndexList"
        immediate-change
        class="picker-view"
        @change="changeHandle"
      >
        <picker-view-column
          v-for="(opt, optIndex) in optionsList"
          :key="optIndex"
        >
          <view
            v-for="(item, index) in opt"
            :key="index"
            class="picker-item"
          >
            {{ item[labelKey] }}
          </view>
        </picker-view-column>
      </picker-view>
      <template v-if="$slots.footer">
        <view class="divider" />
        <slot name="footer" />
        <view class="popper-padding-bottom" />
      </template>
    </view>
  </v-popover>
</template>

<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    modelValue?: boolean;
    isClear?: boolean;
    valueList?: unknown[];
    options: Record<string, unknown>[];
    labelKey?: string;
    valueKey?: string;
    childrenKey?: string;
  }>(),
  {
    modelValue: false,
    isClear: false,
    valueList: undefined,
    options: () => [],
    labelKey: 'label',
    valueKey: 'value',
    childrenKey: 'children'
  }
);

const emits = defineEmits<{
  'update:model-value': [val: boolean];
  'update:value-list': [val: unknown[]];
  change: [val: unknown[]];
  confirm: [val: unknown[]];
}>();

const valueList = toRef(props, 'valueList');
const labelKey = toRef(props, 'labelKey');
const valueKey = toRef(props, 'valueKey');
const childrenKey = toRef(props, 'childrenKey');

const modelValue = toRef(props, 'modelValue');
const isShow = ref(false);
watch([modelValue, valueList], async () => {
  if (modelValue.value) {
    await refreshIndexList();
    isShow.value = true;
  } else {
    isShow.value = false;
  }
});

const updateHandle = (val: boolean) => {
  if (!val) hidePicker();
};
const hidePicker = () => {
  emits('update:model-value', false);
};

const options = toRef(props, 'options') as Ref<Record<string, unknown>[]>;
const optionsIndexList = ref<number[]>([]);

const refreshIndexList = async () => {
  if (!options.value?.length) return;
  const list: number[] = [];
  let rootList = options.value;
  let i = 0;
  while (rootList !== undefined) {
    let index = -1;
    const value = valueList.value?.[i];
    if (value !== undefined) {
      index = rootList.findIndex((item) => item[valueKey.value] === value);
    } else if (optionsIndexList.value[i] !== undefined) {
      index = optionsIndexList.value[i];
    }
    if (index === -1 || rootList[index] === undefined) {
      index = 0;
    }
    list.push(index);
    i += 1;
    const nextList = rootList?.[index]?.[childrenKey.value] as Record<
      string,
      unknown
    >[];
    if (!nextList) break;
    rootList = nextList;
  }
  await nextTick();
  optionsIndexList.value = list;
};

const optionsList = computed(() => {
  if (!options.value?.length) return [];
  const list: Record<string, unknown>[][] = [];
  let rootList = options.value;
  let i = 0;
  while (rootList !== undefined) {
    let index = optionsIndexList.value[i];
    i += 1;
    list.push(rootList);
    if (index === undefined || rootList[index] === undefined) {
      index = 0;
    }
    const nextList = rootList?.[index]?.[childrenKey.value] as
      | Record<string, unknown>[]
      | undefined;
    if (!nextList) break;
    rootList = nextList;
  }
  return list;
});

const changeHandle = (event: PickerViewChangeEvent) => {
  const list: number[] = [];
  const itemList: Record<string, unknown>[] = [];
  const targetList = event.detail.value;
  let nextList: Record<string, unknown>[] | undefined = options.value;
  for (let i = 0; i < targetList.length; i += 1) {
    const index = targetList[i];
    nextList = nextList?.[index]?.[childrenKey.value] as
      | Record<string, unknown>[]
      | undefined;
    if (nextList?.[index]) itemList.push(nextList[index]);
    if (optionsIndexList.value[i] === undefined) {
      list.push(index);
    } else if (optionsIndexList.value[i] !== index) {
      list.push(targetList[i]);
      break;
    } else {
      list.push(index);
    }
  }
  while (nextList !== undefined) {
    list.push(0);
    nextList = nextList?.[0]?.[childrenKey.value] as
      | Record<string, unknown>[]
      | undefined;
  }
  optionsIndexList.value = list;
  emits('change', itemList);
};

const confirmHandle = () => {
  const itemList: Record<string, unknown>[] = [];
  let nextList: Record<string, unknown>[] | undefined = options.value;
  for (let i = 0; i < optionsIndexList.value.length; i += 1) {
    const index = optionsIndexList.value[i];
    const item: Record<string, unknown> = nextList[index];
    if (!item) break;
    itemList.push(item);
    nextList = item?.[childrenKey.value] as
      | Record<string, unknown>[]
      | undefined;
    if (!nextList) break;
  }
  emits('confirm', itemList);
  hidePicker();
};
const clearHandle = () => {
  emits('confirm', []);
  hidePicker();
};
</script>

<style lang="scss" scoped>
.v-picker-container {
  background-color: white;
  border-radius: 16rpx 16rpx 0 0;
  .header {
    height: 80rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    .cancel-button,
    .confirm-button {
      color: #005bac;
      padding: 0 40rpx;
      width: fit-content;
    }
    .clear-button {
      color: red;
    }
    .content {
      flex: 1;
      overflow: hidden;
    }
  }
  .divider {
    height: 1px;
    background-color: #e5e5e5;
  }
  .picker-view {
    height: 500rpx;
    width: 100vw;
    .picker-item {
      height: 80rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
    }
  }
}
</style>
